package org.hishenframework.core.hibernate;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hishenframework.data.Page;

public class EasyOperater {

	@Resource
	private SessionFactory factory;
	
	public <T> List<T> list(String queryString, Object... values) {
		return list(0, -1, queryString, values);
	}

	public void list(Page page, String queryString, Object... values) {
		Long count = uniqueResult("select count(*) " + queryString, values);
		page.setTotalCount(count.intValue());
		page.setResult( list(page.getOffset(), page.getPageSize(), queryString, values) );
	}
	
	public <T> List<T> list(int firstResult, int maxResults, String queryString, Object... values) {
		Session session = factory.getCurrentSession();
		Query query = session.createQuery(queryString);
		query.setFirstResult(firstResult);
		query.setMaxResults(maxResults);
		fillParam(query, values);
		return query.list();
	}
	
	public <T> Iterator<T> iterate(String queryString, Object... values) {
		return iterate(0, -1, queryString, values);
	}
	
	public <T> Iterator<T> iterate(int firstResult, int maxResults, String queryString, Object... values) {
		Session session = factory.getCurrentSession();
		Query query = session.createQuery(queryString);
		query.setFirstResult(firstResult);
		query.setMaxResults(maxResults);
		fillParam(query, values);
		return query.iterate();
	}
	
	/**
	 * 查询唯一结果
	 * 如果有多个值抛错，如果有值且只有一个,返回一个object，如果没值,返回null
	 * @param queryString
	 * @param values
	 * @return 如果有值且只有一个,返回一个object，如果没值,返回null
	 */
	public <T> T uniqueResult(String queryString, Object... values) {
		Session session = factory.getCurrentSession();
		Query query = session.createQuery(queryString);
		fillParam(query, values);
		return (T) query.uniqueResult();
	}
	
	private void fillParam(Query q, Object... vals) {
		for (int i = 0; i < vals.length; i++) {
			if (vals[i] instanceof String) {
				q.setString(i, (String) vals[i]);
				
			} else if (vals[i] instanceof Date) {
				q.setTimestamp(i, (Date) vals[i]);
				
			} else if (vals[i] instanceof Integer) {
				q.setInteger(i, (Integer) vals[i]);
				
			} else if (vals[i] instanceof Boolean) {
				q.setBoolean(i, (Boolean) vals[i]);
				
			} else if (vals[i] instanceof BigDecimal) {
				q.setBigDecimal(i, (BigDecimal) vals[i]);

			} else if (vals[i] instanceof Long) {
				q.setLong(i, (Long) vals[i]);

			} else if (vals[i] instanceof byte[]) {
				q.setBinary(i, (byte[]) vals[i]);

			} else if (vals[i] instanceof Calendar) {
				q.setCalendar(i, (Calendar) vals[i]);

			} else if (vals[i] instanceof Double) {
				q.setDouble(i, (Double) vals[i]);
			
			} else if (vals[i] instanceof Float) {
				q.setFloat(i, (Float) vals[i]);
				
			} else if (vals[i] instanceof Character) {
				q.setCharacter(i, (Character) vals[i]);
				
			} else if (vals[i] instanceof Byte) {
				q.setByte(i, (Byte) vals[i]);
			
			} else {
				throw new RuntimeException("不支持该参数类型。"); 
			}
		}
	}
	
	public <T> T load(Class<T> theClass, int id) {
		Session session = factory.getCurrentSession();
		return (T) session.load(theClass, id);
	}
	
	public <T> T get(Class<T> theClass, int id) {
		Session session = factory.getCurrentSession();
		return (T) session.get(theClass, id);
	}
	
	/**
	 * 保存
	 * @param object
	 * @return
	 */
	public Serializable save(Object object) {
		return factory.getCurrentSession().save(object);
	}
	
	/**
	 * 保存或更新
	 * @param object
	 */
	public void saveOrUpdate(Object object) {
		factory.getCurrentSession().saveOrUpdate(object);
	}
	
	/**
	 * 更新
	 * @param object
	 */
	public void update(Object object) {
		factory.getCurrentSession().update(object);
	}
	
	/**
	 * 删除
	 * @param object
	 */
	public void delete(Object object) {
		factory.getCurrentSession().delete(object);;
	}
	
	/**
	 * 操作
	 * @param hql 
	 * @param values
	 * @return
	 */
	public int executeUpdate(String hql, Object... values) {
		Query query = factory.getCurrentSession().createQuery(hql);
		fillParam(query, values);
		return query.executeUpdate();
	}
}
